import React, {memo} from 'react';
import {shallowEqual, useDispatch, useSelector} from "react-redux";
import {addNumberAction, changeMessageAction, subNumberAction} from "./store/modules/counter";

// memo高阶组件包裹起来的子组件：只有props发生改变时，子组件才会重新渲染
// 问题：当前组件未依赖的 store 中的值发生改变时，也会引起当前组件的重新渲染！
const Home = memo(() => {

  /**
   * 默认情况下，useSelector 监听的是整个 state, 当 state 中任意一个变量发生改变时，当前组件都会重新渲染
   */
  const { message } = useSelector((state) => ({
    message: state.counter.message,
    /**
     * 参数2：可以传入一个函数，该函数会将当前组件依赖的 state 属性进行比较，来决定当前组件是否重新渲染
     * react-redux 为我们提供了一个函数 shallowEqual 可以直接使用
     */
  }), shallowEqual)

  console.log("Home Render")

  const dispatch = useDispatch();
  const changeMessageHandle = () => {
    dispatch(changeMessageAction("Hello World"))
  }

  return (
      <div>
        <h2>Home: {message}</h2>
        <button onClick={changeMessageHandle}>修改文本</button>
      </div>
  )
})


const App = memo((props) => {

  //1.使用 useSelector 将 redux 中的数据映射到组件内
  const { counter } = useSelector((state) => {
    return {
      counter: state.counter.count,
    }
  }, shallowEqual)

  //2.使用 useDispatch 直接获取 dispatch， 通过 dispatch 派发 action 事件
  const dispatch = useDispatch();

  //注：在类组件中不能使用hook，所以在类组件中依然需要使用高阶组件 connect
  const changeNumberHandle = (num, isAdd) => {
    if (isAdd) {
      dispatch(addNumberAction(num));
    } else {
      dispatch(subNumberAction(num));
    }
  }

  console.log("App Render")

  return (
      <div>
        <h2>当前技术: {counter}</h2>
        <button onClick={() => changeNumberHandle(1, true)}>+1</button>
        <button onClick={() => changeNumberHandle(1, false)}>-1</button>
        <Home/>
      </div>
  );
});

export default App;

/**
 * 服务器端渲染（SSR）：
 * 任何一个技术的出现都不是凭空产生的，都是为了解决原有技术上的一些痛点
 * 后端渲染 -> 前后端分离 -> SPA(单页面富应用)
 * SPA存在的问题：
 *  1.首屏的渲染速度
 *  2.SEO优化的问题
 *
 * SPA页面是如何渲染出来的？
 * 浏览器根据域名 -> 服务器 ——> 请求index.html文件 -> SPA中index.html中基本没有什么内容( <div id="root"></div>)
 * -> 客户端下载index.html中的js文件 -> 客户端执行js文件，生成完整的index.html页面结构
 *
 * 1.SEO优化问题(搜索引擎优化)
 * 搜索引擎（百度）爬虫，爬取互联网上网站的数据，其实就是把网站的 index.html 爬取下来（对于SPA index.html中其实没什么内容）
 * 这就导致搜索引擎(百度)数据库中收录的网站信息是很少的（如果再爬取js，执行js，会消耗服务器性能）
 * 当用户在搜索引擎中搜索关键字时，从数据库中匹配网站，因为SPA网页收录的信息较少，就会导致网站排名非常靠后
 * 注：谷歌是会执行js代码，然后对 index.html 中的信息进行收录的，百度不会...
 *
 * 2.首屏渲染速度问题
 * 早期的SSR页面(JSP/PHP/ASP)：是在服务器中把整个页面结构创建好了，当浏览器请求时，会把整个网页结构请求下来
 * 这时候浏览器获取到index.html时，就不需要通过执行js代码创建页面结构了
 * 因为获取到的直接是一个完整的网页结构，所以浏览器直接进行解析渲染就好了
 *
 * SPA:浏览器请求的到index.html后，还要根据<script src="bundle.js">...，把对应的js文件下载下来
 * 而且如果没有进行lazy_load，整个js文件会很大，导致下载速度很慢。
 * 而且下载完之后，还要由浏览器执行bundle.js中的代码（document.createElement(...)），构建index.html界面结构
 * 这时候浏览器才能进行页面解析，渲染页面
 *
 * 服务器端渲染：在服务器中我们可以借助 Node 来帮我们执行 JavaScript 代码，提前完成.html页面结构的生成，然后返回给客户端浏览器
 * 浏览器直接进行页面解析渲染就ok了。
 */

/**
 * SSR同构应用
 *
 * 1.什么是同构？
 * 一套代码既可以在服务端运行又可以在客户端运行，这就是同构应用
 *
 * 2.为什么要在浏览器上再运行一遍？
 * 在服务器端渲染出来的SSR，只是一堆html字符串，是没有绑定js的动态操作的
 * 比如：button点击时, 需要调用js方法做出某些操作
 * 而服务器端渲染所执行的js，只是出于展示页面的目的，并没有执行动态操作的js
 * 在浏览器上运行js，是为了把交互性操作的js，注入到网站上面
 *
 * 3.hydrate: 注入
 * 在进行SSR时，我们的页面呈现为HTML
 * 但仅HTML不足以使页面具有交互性，浏览器端 JavaScript 为零的页面是不能交互的
 * 为了使我们的页面具有交互性，除了在 Node.js 中将页面呈现为 HTML 之外，
 * 我们的UI框架还要在浏览器中加载和呈现的页面中注入交互性
 * 这个注入的过程就称为 hydration
 */